use core::arch::{asm, naked_asm};

#[inline(never)]
#[unsafe(no_mangle)]
pub fn h3_14_1() {
    let out1: usize;
    let out2: usize;
    let out3: usize;
    let out4: usize;
    let out5: usize;
    let out6: usize;
    unsafe {
        asm!(            "li a0, 0x80200000", //  使用li指令把0x80200000加载到a0寄存器

            "mv {0}, a0",
            "li a1, 16",         // 把16加载到a1寄存器
            "mv {1}, a1",
            "lwu t0, 0(a0)",     // 从0x80200000读取4字节数据
            "mv {2}, t0",
            "ld t0, 16(a0)",     // 从0x80200010读取8字节数据
            "mv {3}, t0",
            "lui t0, 0x8034f",   // lui加载立即数0x8034f到t0
            "mv {4}, t0",
            "lui t1, 0x400",     // lui加载立即数0x400到t1,
            "mv {5}, t1",
            out(reg) out1,
            out(reg) out2,
            out(reg) out3,
            out(reg) out4,
            out(reg) out5,
            out(reg) out6
        );
    }
    println!("0x80200000加载到a0寄存器后的值为: 0x{:x}", out1);
    println!("16加载到a1寄存器后，a1寄存器的值为: 0x{:x}", out2);
    println!("从0x80200000读取4个字节，整数值为: 0x{:x}", out3);
    println!("从0x80200010读取8个字节，整数值为: 0x{:x}", out4);
    println!(
        "lui把0x8034f加载到t0寄存器，现在寄存器值是0xffffffff8034f000吗? {}",
        out5 == 0xffffffff8034f000
    );
    println!(
        "lui把0x400加载到t1寄存器，现在寄存器的值是0x10000000吗? {}",
        out6 == 0x400000
    );
}

/// 实现一个memcpy的汇编函数
#[inline(never)]
#[unsafe(export_name = "memcpy")]
pub fn h3_14_3() {
    unsafe {
        asm!(
            r#"
            li t0, 0x80200000
            li t6, 0x80210000
            li t1, 32
            mv t2, zero
            loop: 
              lbu t2, (t0)
              sb t2, (t6)
              addi t2, t2, 1
              add t0, t0, 1
              add t6, t6, 1
              bne t2, t1, loop
            "#
        );
    }
    // 验证
    let addr = 0x80200000 as *const u8;
    let mut ret = [0u8; 32];
    unsafe {
        core::ptr::copy(addr, &raw mut ret[0], 32);
    }
    println!("0x80200000处的32字节的数据为");
    ret.iter().for_each(|x| {
        print!("0x{:x},", x);
    });

    let target_addr = 0x80210000 as *const u8;
    let mut target = [0u8; 32];
    unsafe {
        core::ptr::copy(target_addr, &raw mut target[0], 32);
    }
    println!("");
    println!("0x80210000处的32字节的数据为: ");
    target.iter().for_each(|x| {
        print!("0x{:x},", x);
    });
    println!("");
}

/// 实现c语言的memset原型。要求有16字节对齐
#[inline(never)]
#[unsafe(export_name = "memset")]
pub fn h3_14_4(dst: *mut u8, value: u8, count: usize) {
    unsafe {
        asm!(
            r#"
                h3_14_4_loop:
                    sb a1, 0(a0)
                    addi a0, a0, 1
                    addi a2, a2, -1
                    bne a2, zero, h3_14_4_loop
            "#,
            in("t0") dst,
            in("t1") value,
            in("t2") count,
        );
    }
}

///
#[inline(never)]
#[unsafe(export_name = "compare_and_return")]
pub fn h3_14_5(a: usize, b: usize) -> usize {
    let ret: usize;
    unsafe {
        asm!(
            r#"
                bgeu {0}, {1}, compare_and_return_gte
                li t0, 0xffffffffffffffff
                mv {2}, t0
                j compare_and_return_over
                compare_and_return_gte:
                    mv {2}, zero
                compare_and_return_over:
            "#,
            in(reg) a,
            in(reg) b,
            out(reg) ret,
        );
    }
    //println!("ret: 0x{:x}", ret);
    ret
}

/// 这是一个汇编级别的函数
/// 有两个参数：a:usize, b: usize
/// 一个返回usize
#[naked]
#[unsafe(export_name = "sel_test")]
pub unsafe extern "C" fn h3_14_6() {
    unsafe {
        naked_asm!(
            "sd ra, -8(sp)",  // 压入 ra
            "sd s0, -16(sp)", // 压入 s0
            "sd s1, -24(sp)", // 压入 s1
            r#"
                mv s0, a0
                mv s1, a1
                beq s0, zero, h3_14_6_1
                bne s0, zero, h3_14_6_2
                h3_14_6_1:
                    addi a0, s1, 2
                    j h3_14_6_2_over
                h3_14_6_2:
                    addi a0, s1, -1
                h3_14_6_2_over:
                /*弹出*/
                ld s1, -24(sp)
                ld s0, -16(sp)
                ld ra, -8(sp)
                ret
            "#
        );
    }
}

#[naked]
#[unsafe(export_name = "bl_test")]
pub unsafe extern "C" fn h3_14_7(n: usize) {
    unsafe {
        naked_asm!("li t0, 0x90", "ret",);
    }
}
